﻿//--------------------------------------------------------------------------
// <copyright file="AntiXss.cs" company="Microsoft">
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// </copyright>
// <summary>AntiXss</summary>
//--------------------------------------------------------------------------
namespace MS.Msn.MediaSolutions.Common.Web
{
    using System;
    using System.Text;
    using System.Reflection;
    using System.Collections;
    using System.Collections.Generic;

    /// <summary>
    /// Anti Cross Site Scripting
    /// </summary>
    public static class AntiXss
    {
        #region auto encode by reflection - added by Rex.Sun

        /// <summary>
        /// EncodeType
        /// </summary>
        public enum EncodeType
        {
            /// <summary>
            /// Html 
            /// </summary>
            Html,

            /// <summary>
            /// HtmlAttribute
            /// </summary>
            HtmlAttribute,

            /// <summary>
            /// JavaScript
            /// </summary>
            JavaScript,

            /// <summary>
            /// VbScript
            /// </summary>
            VbScript,

            /// <summary>
            /// Xml
            /// </summary>
            Xml,

            /// <summary>
            /// XmlAttribute
            /// </summary>
            XmlAttribute,

            /// <summary>
            /// Url
            /// </summary>
            Url
        }

        /// <summary>
        /// Encode
        /// </summary>
        /// <typeparam name="T">object type</typeparam>
        /// <param name="obj">object instance</param>
        /// <param name="enType">encode type</param>
        /// <param name="ignores">ignore properties</param>
        /// <returns>encoded object</returns>
        public static T Encode<T>(T obj, EncodeType enType, IList<string> ignores)
        {
            T rtval = obj;
            Type tp = typeof(T);

            if (obj != null && !tp.IsValueType)
            {
                MemberInfo[] members = tp.GetMembers(BindingFlags.Instance | BindingFlags.Public);
                foreach (MemberInfo member in members)
                {
                    if (ignores != null && ignores.Contains(member.Name))
                    {
                        continue;
                    }

                    string value = string.Empty;
                    FieldInfo fi = member as FieldInfo;
                    PropertyInfo pi = member as PropertyInfo;

                    if ((fi != null))
                    {
                        if (fi.FieldType == typeof(string) || fi.FieldType == typeof(char))
                        {
                            value = Convert.ToString(fi.GetValue(obj), Apps.DefaultCulture);
                            fi.SetValue(obj, Encode(value, enType));
                        }
                    }

                    if (pi != null)
                    {
                        Object[] oref = new Object[0];
                        if (pi.PropertyType == typeof(string) || pi.PropertyType == typeof(char))
                        {
                            value = Convert.ToString(pi.GetValue(obj, oref), Apps.DefaultCulture);
                            pi.SetValue(obj, Encode(value, enType), oref);
                        }
                    }
                }
            }

            return rtval;
        }

        /// <summary>
        /// Encode
        /// </summary>
        /// <typeparam name="T">object type</typeparam>
        /// <param name="obj">object instance</param>
        /// <param name="enType">encode type</param>
        /// <returns>encoded object</returns>
        public static T Encode<T>(T obj, EncodeType enType)
        {
            return Encode<T>(obj, enType, null);
        }

        /// <summary>
        /// Encode
        /// </summary>
        /// <param name="strInput">input string</param>
        /// <param name="enType">encode type</param>
        /// <returns>encoded string</returns>
        public static string Encode(string strInput, EncodeType enType)
        {
            string rtval = strInput;

            switch (enType)
            {
                case EncodeType.Html:
                    rtval = EncodeHtml(strInput);
                    break;

                case EncodeType.HtmlAttribute:
                    rtval = EncodeHtmlAttribute(strInput);
                    break;

                case EncodeType.Xml:
                    rtval = EncodeXml(strInput);
                    break;

                case EncodeType.XmlAttribute:
                    rtval = EncodeXmlAttribute(strInput);
                    break;

                case EncodeType.JavaScript:
                    rtval = EncodeJs(strInput);
                    break;

                case EncodeType.Url:
                    rtval = EncodeUrl(strInput);
                    break;

                case EncodeType.VbScript:
                    rtval = EncodeVbs(strInput);
                    break;
            }

            return rtval;
        }

        #endregion

        private const string EmptyString_JavaScript = "''";
        private const string EmptyString_VBS = "\"\"";

        private static string EncodeHtml(string strInput)
        {
            if (strInput == null)
            {
                return null;
            }
            if (strInput.Length == 0)
            {
                return string.Empty;
            }
            StringBuilder builder = new StringBuilder("", strInput.Length * 2);
            foreach (char ch in strInput)
            {
                if ((((ch > '`') && (ch < '{')) || ((ch > '@') && (ch < '['))) || (((ch == ' ') || ((ch > '/') && (ch < ':'))) || (((ch == '.') || (ch == ',')) || ((ch == '-') || (ch == '_')))))
                {
                    builder.Append(ch);
                }
                else
                {
                    builder.Append("&#" + ((int)ch).ToString(Apps.DefaultCulture) + ";");
                }
            }
            return builder.ToString();
        }

        private static string EncodeHtmlAttribute(string strInput)
        {
            if (strInput == null)
            {
                return null;
            }
            if (strInput.Length == 0)
            {
                return string.Empty;
            }
            StringBuilder builder = new StringBuilder("", strInput.Length * 2);
            foreach (char ch in strInput)
            {
                if ((((ch > '`') && (ch < '{')) || ((ch > '@') && (ch < '['))) || (((ch > '/') && (ch < ':')) || (((ch == '.') || (ch == ',')) || ((ch == '-') || (ch == '_')))))
                {
                    builder.Append(ch);
                }
                else
                {
                    builder.Append("&#" + ((int)ch).ToString(Apps.DefaultCulture) + ";");
                }
            }
            return builder.ToString();
        }

        private static string EncodeJs(string strInput)
        {
            if (strInput == null)
            {
                return null;
            }
            if (strInput.Length == 0)
            {
                return "''";
            }
            StringBuilder builder = new StringBuilder("'", strInput.Length * 2);
            foreach (char ch in strInput)
            {
                if ((((ch > '`') && (ch < '{')) || ((ch > '@') && (ch < '['))) || (((ch == ' ') || ((ch > '/') && (ch < ':'))) || (((ch == '.') || (ch == ',')) || ((ch == '-') || (ch == '_')))))
                {
                    builder.Append(ch);
                }
                else if (ch > '\x007f')
                {
                    builder.Append(@"\u" + TwoByteHex(ch));
                }
                else
                {
                    builder.Append(@"\x" + SingleByteHex(ch));
                }
            }
            builder.Append("'");
            return builder.ToString();
        }

        private static string EncodeUrl(string strInput)
        {
            if (strInput == null)
            {
                return null;
            }
            if (strInput.Length == 0)
            {
                return string.Empty;
            }
            StringBuilder builder = new StringBuilder("", strInput.Length * 2);
            foreach (char ch in strInput)
            {
                if ((((ch > '`') && (ch < '{')) || ((ch > '@') && (ch < '['))) || (((ch > '/') && (ch < ':')) || (((ch == '.') || (ch == '-')) || (ch == '_'))))
                {
                    builder.Append(ch);
                }
                else if (ch > '\x007f')
                {
                    builder.Append("%u" + TwoByteHex(ch));
                }
                else
                {
                    builder.Append("%" + SingleByteHex(ch));
                }
            }
            return builder.ToString();
        }

        private static string EncodeVbs(string strInput)
        {
            if (strInput == null)
            {
                return null;
            }
            if (strInput.Length == 0)
            {
                return "\"\"";
            }
            StringBuilder builder = new StringBuilder("", strInput.Length * 2);
            bool flag = false;
            foreach (char ch in strInput)
            {
                if ((((ch > '`') && (ch < '{')) || ((ch > '@') && (ch < '['))) || (((ch == ' ') || ((ch > '/') && (ch < ':'))) || (((ch == '.') || (ch == ',')) || ((ch == '-') || (ch == '_')))))
                {
                    if (!flag)
                    {
                        builder.Append("&\"");
                        flag = true;
                    }
                    builder.Append(ch);
                }
                else
                {
                    if (flag)
                    {
                        builder.Append("\"");
                        flag = false;
                    }
                    builder.Append("&chrw(" + ((uint)ch).ToString(Apps.DefaultCulture) + ")");
                }
            }
            if ((builder.Length > 0) && (builder[0] == '&'))
            {
                builder.Remove(0, 1);
            }
            if (builder.Length == 0)
            {
                builder.Insert(0, "\"\"");
            }
            if (flag)
            {
                builder.Append("\"");
            }
            return builder.ToString();
        }

        private static string EncodeXml(string strInput)
        {
            return EncodeHtml(strInput);
        }

        private static string EncodeXmlAttribute(string strInput)
        {
            return EncodeHtmlAttribute(strInput);
        }

        /// <summary>
        /// HtmlAttributeEncode
        /// </summary>
        /// <param name="s">s</param>
        /// <returns>encoded s</returns>
        public static string HtmlAttributeEncode(string s)
        {
            return EncodeHtmlAttribute(s);
        }

        /// <summary>
        /// HtmlEncode
        /// </summary>
        /// <param name="s">s</param>
        /// <returns>encoded s</returns>
        public static string HtmlEncode(string s)
        {
            return EncodeHtml(s);
        }

        /// <summary>
        /// JavaScriptEncode
        /// </summary>
        /// <param name="s">s</param>
        /// <returns>encoded s</returns>
        public static string JavaScriptEncode(string s)
        {
            return EncodeJs(s);
        }

        private static string SingleByteHex(char c)
        {
            uint num = c;
            return num.ToString("x", Apps.DefaultCulture).PadLeft(2, '0');
        }

        private static string TwoByteHex(char c)
        {
            uint num = c;
            return num.ToString("x", Apps.DefaultCulture).PadLeft(4, '0');
        }

        /// <summary>
        /// UrEncode
        /// </summary>
        /// <param name="s">s</param>
        /// <returns>encoded s</returns>
        public static string UrEncode(string s)
        {
            return EncodeUrl(s);
        }

        /// <summary>
        /// VisualBasicScriptEncode
        /// </summary>
        /// <param name="s">s</param>
        /// <returns>encoded s</returns>
        public static string VisualBasicScriptEncode(string s)
        {
            return EncodeVbs(s);
        }

        /// <summary>
        /// XmlAttributeEncode
        /// </summary>
        /// <param name="s">s</param>
        /// <returns>encoded s</returns>
        public static string XmlAttributeEncode(string s)
        {
            return EncodeXmlAttribute(s);
        }

        /// <summary>
        /// XmlEncode
        /// </summary>
        /// <param name="s">s</param>
        /// <returns>encoded s</returns>
        public static string XmlEncode(string s)
        {
            return EncodeXml(s);
        }
    }
}